
#include <xthread/guard.hpp>

#include "naming_strategy.hpp"
#include "table_schema_manager.hpp"
#include "table_schema.hpp"
#include "global.hpp"

#include "kv_scan_context.hpp"

namespace xbase
{

	kv_scan_context::kv_scan_context (const std::string &p_tablet_name,
					  const std::string &p_start_row,
					  const std::string &p_end_row,
					  const std::vector<std::string> &p_columns,
					  uint64_t p_latest_timestamp,
					  uint64_t p_oldest_timestamp,
					  uint32_t p_ttl,
					  uint32_t p_num_version,
					  uint32_t p_options,
					  uint32_t p_num_row)
		: m_table_name(naming_strategy::get_table_name_from_tablet_name(p_tablet_name))
		, m_schema()
		, m_id(uuid::instance().get())
		, m_last_used_time(cur_seconds())
		, m_tablet_name(p_tablet_name)
		, m_start_row(p_start_row)
		, m_end_row(p_end_row)
		, m_columns(p_columns)
		, m_latest_timestamp(p_latest_timestamp)
		, m_oldest_timestamp(p_oldest_timestamp)
		, m_ttl(uint64_t(p_ttl) * 1000ULL * 1000ULL)
		, m_num_version(p_num_version)
		, m_options(p_options)
		, m_num_row(p_num_row)
		, m_need_check_timestamp((p_latest_timestamp != NO_TIMESTAMP)
					 || (p_oldest_timestamp != NO_TIMESTAMP)
					 || (p_ttl != 0))
		, m_need_check_version(p_num_version != ALL_VERSION)
		, m_filter_deleted_enabled(filter_deleted_option_enabled(p_options))
		, m_filter_deleted_itself_enabled(filter_deleted_itself_option_enabled(p_options))
		, m_filter_value_disabled(filter_value_option_disabled(p_options))
		, m_is_contain_all_columns(false)
	{
		const std::vector<std::string>::iterator end = m_columns.end();
		std::vector<std::string>::iterator iter = m_columns.begin();
		
		table_schema::pointer schema = get_schema();

		std::size_t least_index = 0;
		std::set<std::string> group_filter;
		for(; iter != end; ++iter)
		{
			column_name_parser cr(*iter);
			m_column_name_parser.push_back(cr);

			if(cr.is_any_column()) // 只要有一个列名是星号，就包含所有的列
			{
				m_is_contain_all_columns = true;
			}
			else
			{
				// 保存相应的组名
				const std::string family = cr.family_name();
				const std::string group = schema->which_group(family);
				if(group.empty())
				{
					m_bad_family.push_back(family);

					LOG(ERROR, "kv_scan_context::kv_scan_context not find group for family "
					    << family);
				}
				else
				{
					std::pair<std::set<std::string>::iterator, bool>
						ret = group_filter.insert(group);
					if(ret.second == true) // 只在不存在时，才加入到组列表中
					{
						m_groups.push_back(group);
					}
				}
			}

			// 始终保持least_index指向最小的列名对应的
			// column_name_parser的下标。最小的列是星号列，或者列
			// 族最小的列，或者整列最小的列，总之要分开比
			// 较，不能仅比较列字符串
			// 
			// 已经指向星号列了，是无穷小的列了，就不再找了
			if(! m_column_name_parser[least_index].is_any_column())
			{
				if(cr.is_any_column()) // 如果当前列是星号，则它就是最小列
				{
					least_index = m_column_name_parser.size() - 1;
				}
				else // 当前列有列族名
				{
					if(m_column_name_parser[least_index].is_any_qualifier()) // 如果找到的列只有列族，则只比较列族即可
					{
						if(cr.family_name() < m_column_name_parser[least_index].family_name())
						{
							// 列族名小，则就是小了
							least_index = m_column_name_parser.size() - 1;
						}
						// 列族名相等，则只可能是相等或大于，因为找到的列没有小列名
						// 列族名大，则不考虑了
					}
					else // 找到的列是完全的列名，则先比较列族名，再比较小列名
					{
						if(cr.family_name() < m_column_name_parser[least_index].family_name())
						{
							// 列族名小，则就是小了
							least_index = m_column_name_parser.size() - 1;
						}
						else if(cr.family_name() == m_column_name_parser[least_index].family_name())
						{
							// 列族名相等，则需要比较小列名
							if(cr.is_any_qualifier()
							   || (cr.qualifier_name() < m_column_name_parser[least_index].qualifier_name()))
							{
								// 当前列没有小列名，或者小列名小，则是小
								least_index = m_column_name_parser.size() - 1;
							}
							// 否则，不是更小的列
						}
						// 列族名大，则不考虑了
					}
				}
			}
		}

		m_least_column_name_parser = m_column_name_parser[least_index];
	}
	
	table_schema::pointer kv_scan_context::get_schema() const
	{
		if (m_schema.expired())
		{
			Guard<FastLock> _guard(m_schema_lock);
			if (m_schema.expired())
			{
				m_schema = global::the_schema_manager->get_schema(m_table_name);
			}
		}
		return m_schema.lock();
	}

	std::string kv_scan_context::to_string() const
	{
		std::ostringstream out;
		out << "{table_name: " << m_table_name
		    << "; id: " << m_id
		    << "; m_last_used_time: " << m_last_used_time
		    << "; tablet_name: " << m_tablet_name
		    << "; start_row: " << m_start_row
		    << "; end_row: " << m_end_row
		    << "; columns: " << m_columns
		    << "; latest_timestamp: " << m_latest_timestamp
		    << "; oldest_timestamp: " << m_oldest_timestamp
		    << "; num_version: " << m_num_version
		    << "; options: 0x" << std::hex << m_options << std::dec
		    << "; num_row: " << m_num_row
		    << "; need_check_timestamp: " << m_need_check_timestamp
		    << "; need_check_version: " << m_need_check_version
		    << "; filter_deleted: " << m_filter_deleted_enabled
		    << "; filter_deleted_itself: " << m_filter_deleted_itself_enabled
		    << "; m_is_contain_all_columns: " << m_is_contain_all_columns
		    << "; m_least_column: " << m_least_column_name_parser.column_name()
		    << "; m_groups: " << m_groups
		    << "; m_bad_family: " << m_bad_family
		    << "}";
		return out.str();
	}
} // namespace xbase
